#!/bin/bash

TEMP=$(getopt -o t::l::y::b::I::d --long testdir::,logdir::,inou::,binary::,incdir::,debug,s_lgdb::,e_lgdb::,bounds::,top::,lib::,constr::,freq::,lgraph:: -n 'lgsetup' -- "$@")
eval set -- "$TEMP"

OPT_YOSYS="yosys"
OPT_TESTDIR="./tests"
OPT_LOGDIR="./logs"
OPT_SLGDB="./lgdb_synth"
OPT_ELGDB="./lgdb_elab"
OPT_INOU_YOSYS="./inou/yosys/liblgraph_yosys.so"
OPT_DEBUG=0
OPT_TO_VERILOG=0
OPT_GRAPH_INPUT=""
OPT_LIB=""
OPT_CONSTR=""
OPT_INCDIR=""
OPT_CELL="./inou/yosys/simcell.v"
OPT_TOP=""
OPT_FREQ="100"
OPT_BOUNDS="${OPT_LOGDIR}/bounds"
OPT_LGRAPH="."

while true ; do
    case "$1" in
        -t|--testdir)
            case "$2" in
                "") shift 2 ;;
                *) OPT_TESTDIR=$2 ; shift 2 ;;
            esac ;;
        -b|--binary)
            case "$2" in
                "") shift 2 ;;
                *) OPT_YOSYS=$2 ; shift 2 ;;
            esac ;;
        -l|--logdir)
            case "$2" in
                "") shift 2 ;;
                *) OPT_LOGDIR=$2 ; shift 2 ;;
            esac ;;
        -I|--incdir)
            case "$2" in
                "") shift 2 ;;
                *) OPT_INCDIR="verilog_defaults -add -I$2" ;
                shift 2 ;;
            esac ;;
        --lgraph)
            case "$2" in
                "") shift 2 ;;
                *) OPT_LGRAPH=$2;
                shift 2 ;;
            esac ;;
        --s_lgdb)
            case "$2" in
                "") shift 2 ;;
                *) OPT_SLGDB=$2 ; shift 2 ;;
            esac ;;
        --e_lgdb)
            case "$2" in
                "") shift 2 ;;
                *) OPT_ELGDB=$2 ; shift 2 ;;
            esac ;;
        --top)
            case "$2" in
                "") shift 2 ;;
                *) OPT_TOP=$2 ; shift 2 ;;
            esac ;;
        --lib)
            case "$2" in
                "") shift 2 ;;
                *) OPT_LIB=$2 ; shift 2 ;;
            esac ;;
        --constr)
            case "$2" in
                "") shift 2 ;;
                *) OPT_CONSTR=$2 ; shift 2 ;;
            esac ;;
        --freq)
            case "$2" in
                "") shift 2 ;;
                *) OPT_FREQ=$2 ; shift 2 ;;
            esac ;;
        --bounds)
            case "$2" in
                "") shift 2 ;;
                *) OPT_BOUNDS=$2 ; shift 2 ;;
            esac ;;
        -d|--debug)
          shift 1 ;
          OPT_DEBUG=1 ;;
        -y|--inou)
            case "$2" in
                "") shift 2 ;;
                *) OPT_INOU_YOSYS=$2 ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done
OPT_FILES=$*

if [ ! -f "${OPT_YOSYS}" ]; then
  if [ -x "/usr/bin/yosys" ]; then
    OPT_YOSYS=/usr/bin/yosys
  elif [ -x "/usr/local/bin/yosys" ]; then
    OPT_YOSYS=/usr/local/bin/yosys
  else
    echo "lgyosys: unable to fix OPT_YOSYS path"
    exit 5
  fi
fi

echo "yosys:" $OPT_YOSYS
if [ ! -f "${OPT_YOSYS}" ]; then
  echo $PWD
  echo "Could not find yosys binary in ${OPT_YOSYS}"
  exit 3
fi

if [ -d "${OPT_TESTDIR}" ]; then
  FILE_LIST=$(find ${OPT_TESTDIR} -name '*.v' -o -name '*.vh' -o -name '*.sv' | awk '{print "read_verilog -sv -nomeminit "$1";"}')
	BASE=$(basename ${OPT_TESTDIR})
elif [ "${OPT_FILES}" != "" ]; then
	FILE_LIST=$(echo $OPT_FILES | tr ' ' '\n' | awk '{print "read_verilog -sv -nomeminit "$1";"}')
	for a in ${OPT_FILES}; do
		if [ ! -f "${a}" ]; then
			echo "Could not open source file: ${OPT_FILES}"
		fi
		BASE=$(basename $a)
	done
else
	echo "Specify a list of files to process. Either --testdir=foo or bar.v foo.v"
	exit 4
fi

if [ $OPT_DEBUG -eq 1 ]; then
  OPT_YOSYS="gdb --args ${OPT_YOSYS}"
fi


YOSYS_LIB="/usr/local/share/yosys/"
if [ ! -d ${YOSYS_LIB} ]; then
  echo "ERROR: could not find yosys library files installed"
  exit 1
fi

LGSHELL=${OPT_LGRAPH}/bazel-bin/main/lgshell
if [ ! -f ${LGSHELL} ]; then
  if [ -f ${OPT_LGRAPH}/main/lgshell ]; then
    LGSHELL=${OPT_LGRAPH}/main/lgshell
  else
    echo "could not find lgshell on $(pwd)"
    exit 1
  fi
fi

if [ ! -f ${OPT_INOU_YOSYS} ]; then
  OPT_INOU_YOSYS="${OPT_LGRAPH}/bazel-bin/inou/yosys/liblgraph_yosys.so"
fi

mkdir -p ${OPT_ELGDB}
mkdir -p ${OPT_SLGDB}
mkdir -p ${OPT_LOGDIR}

tmap=""

if [ "$OPT_LIB" == "fpga" ]; then
  libfiles="read_verilog -lib +/xilinx/cells_sim.v; read_verilog -lib +/xilinx/cells_xtra.v; read_verilog -lib +/xilinx/brams_bb.v; read_verilog -lib +/xilinx/drams_bb.v ;"
  tmap="memory_bram -rules +/xilinx/brams.txt; techmap -map +/xilinx/brams_map.v; memory_bram -rules +/xilinx/drams.txt; techmap -map +/xilinx/drams_map.v; opt -fast -full; memory_map; dffsr2dff; dff2dffe; opt -full; techmap -map +/techmap.v -map +/xilinx/arith_map.v; opt  -fast; techmap -D ALU_RIPPLE; opt -fast; abc -D 100 ${OPT_FREQ};"

  ruby ${OPT_LGRAPH}/inou/tech/verilog_json.rb ${YOSYS_LIB}/simcells.v   \
                                               ${YOSYS_LIB}/xilinx/cells_sim.v  \
                                               ${YOSYS_LIB}/xilinx/brams_bb.v   \
                                               ${YOSYS_LIB}/xilinx/drams_map.v > ${OPT_SLGDB}/tech_library

elif [ "$OPT_LIB" != "" ]; then
  sh   ${OPT_LGRAPH}/inou/tech/func_liberty_json.sh ${OPT_LIB} > ${OPT_SLGDB}/tech_library
  abc_script="-D ${OPT_FREQ} -liberty ${OPT_LIB} -constr ${constraint_file}"
  tmap="dffsr2dff; techmap -map +/techmap.v; opt -fast; dfflibmap -liberty ${OPT_LIB}; memory; dfflibmap -liberty ${OPT_LIB};  opt -fast; opt -full; techmap -D ALU_RIPPLE; abc ${abc_script}"

else
  abc_script="-D ${OPT_FREQ}"
  tmap="dffsr2dff; techmap -map +/techmap.v; opt -fast; memory; opt -fast; opt -full; techmap -D ALU_RIPPLE; abc ${abc_script}"

fi

elab_script="hierarchy -top ${OPT_TOP}; select -assert-any ${OPT_TOP}; select -clear; proc_arst; proc; opt -fast; pmuxtree; memory -nomap;"
synth_script="hierarchy -check -top ${OPT_TOP}; proc; flatten; opt -fast; synth -run coarse; opt -fast; opt;  ${tmap}; opt -fast; stat"

yosys_cmd="${OPT_INCDIR}; ${FILE_LIST};
       ${elab_script}; write_verilog ${OPT_ELGDB}/${BASE}_elab.v; yosys2lg -path ${OPT_ELGDB} ;
       ${synth_script}; yosys2lg -path ${OPT_SLGDB};
       setundef -zero; write_verilog -noattr ${OPT_SLGDB}/${BASE}_synth.v"

echo "${OPT_YOSYS} -ql ${OPT_LOGDIR}/${BASE}_lgsetup.log -m ${OPT_INOU_YOSYS} -p \"${yosys_cmd}\"" > ${OPT_LOGDIR}/${BASE}_synth_cmd
${OPT_YOSYS} -ql ${OPT_LOGDIR}/${BASE}_lgsetup.log -m ${OPT_INOU_YOSYS} -p "${yosys_cmd}" > ${OPT_LOGDIR}/${BASE}_log 2> ${OPT_LOGDIR}/${BASE}_err

if [ $? -ne 0 ]; then
  echo "FAILED: was not able to create a graph for ${BASE}"
  exit 1
else
  echo "SUCCESS: created graph for ${BASE}"
fi


echo "echo \"live.invariant_find elab_lgdb:${OPT_ELGDB} synth_lgdb:${OPT_SLGDB} top:${OPT_TOP} invariant_file:${OPT_BOUNDS} hier_sep:\\\".\\\"\" | ${LGSHELL}" > ${OPT_LOGDIR}/${BASE}_invariant_cmd
echo "live.invariant_find elab_lgdb:${OPT_ELGDB} synth_lgdb:${OPT_SLGDB} top:${OPT_TOP} invariant_file:${OPT_BOUNDS} hier_sep:\".\"" | ${LGSHELL}

if [ $? -ne 0 ]; then
  echo "FAILED: was not able to run setup for ${BASE}"
  exit 1
else
  echo "SUCCESS: setup finished for ${BASE}"
fi

